///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2007-2009 ILOG, S.A.
//  All Rights Reserved.
//  The following is ILOG Source Code.  No modifications may be made to the  
//  ILOG Source Code.  Any usage of the ILOG Source Code is subject to 
//  the terms and conditions of the ILOG End User License Agreement   
//  applicable to this ILOG software product.
//
///////////////////////////////////////////////////////////////////////////////

package ilog.gauges.gaugesClasses
{
  import ilog.gauges.TickItem;

  /**
   * The <code>LogScale</code> class maps numeric values evenly
   * between a minimum and a maximum value along a gauge scale.
   * If no <code>majorTickInterval</code> is specified, the scale will place
   * a tick on each power of 10 value (1, 10, 100, 1000, and so on) between
   * the minimum and maximum values.
   *  
   * @mxml
   *  
   * <p>The <code>&lt;LogScale&gt;</code> tag inherits all the properties
   * of its parent classes and adds the following properties:</p>
   *  
   * <pre>
   * &lt;LogScale
   *   <strong>Properties</strong>
   *   majorTickInterval="NaN"
   * /&gt;
   * </pre>
   *  
   * @see ilog.gauges.circular.CircularLogScale
   * @see ilog.gauges.rectangular.RectangularLogScale 
   */
  public class LogScale extends NumericScale
  {
    /**
     * Constructor
     */
    public function LogScale()
    {
      super();  
    }

    /**
     *  @private
     */
    private var _majorTickInterval:Number = NaN;
    
    [Inspectable(category="Gauge")]       

    /**
     * Specifies the multiplier used to compute the interval between two values
     * on the logarithmic scale.
     * If no <code>majorTickInterval</code> is specified, the scale will place
     * a tick on each power of 10 value (1, 10, 100, 1000, and so on) between
     * the minimum and maximum values.
     * A value of 10 generates ticks at 1, 10, 100, 1000, and so on. 
     * A value of 100 generates ticks at 1, 100, 10000, and so on.
     * Intervals must be even powers of 10 and must be greater than or equal to 10.
     * The <code>LogScale</code> rounds the interval down to an even power of 10, if necessary.
     *
     * @default NaN
     */
    public function get majorTickInterval():Number
    {
      return _majorTickInterval;
    }
    
    /**
     * @private
     */
    public function set majorTickInterval(value:Number):void
    {
      _majorTickInterval = value;
      if (isNaN(value))
        _computedMajorTickInterval = 1;
      else
        _computedMajorTickInterval = Math.max(1, Math.floor(Math.log(_majorTickInterval + 0.000001) / Math.LN10));
      invalidateTicks();
    }
    
    /**
     *  @private
     */
    private var _computedMajorTickInterval:Number = NaN;
    
    /**
     *  @private
     */    
    private function get computedMajorTickInterval():Number
    {
      if (isNaN(_computedMajorTickInterval))
        _computedMajorTickInterval = 1;        
      return _computedMajorTickInterval;
    }

    /**
     * The computed minimum value of the scale. If the <code>minimum</code> value is not
     * an even power of 10, the scale computes a new minimum so that it maps to 
     * an even power of 10.
     */
    public function get computedMinimum():Number
    {
      return Math.pow(10, Math.max(0, Math.floor(Math.log(minimum + 0.000001) / Math.LN10))); 
    }

    /**
     * The computed maximum value of the scale. If the <code>maximum</code> value is not
     * an even power of 10, the scale computes a new maximum so that it maps to 
     * an even power of 10.
     */
    public function get computedMaximum():Number
    {
      return Math.pow(10, Math.max(0, Math.floor(Math.log(maximum + 0.000001) / Math.LN10))); 
    }

    /**
     *  @private
     */
    override protected function buildMajorTickItems():Array
    {
      var majorTickCache:Array = [];
      if (maximum > minimum) {
        var start:Number = Math.max(0, Math.floor(Math.log(minimum + 0.000001) / Math.LN10));
        var end:Number = Math.max(0, Math.floor(Math.log(maximum + 0.000001) / Math.LN10));      
        var data:TickItem;
        var interval:Number = computedMajorTickInterval;
        for (var i:int = start; i <= end; i += interval) {
          data = new TickItem(this);
          data.isMinor = false;
          data.value = Math.pow(10, i);
          data.position = (i - start) / (end - start);
          majorTickCache.push(data); 
        }
      }
      return majorTickCache;
    }
  }
}
